﻿#region Copyright (c) 2000-2008 Developer Express Inc.
/*
{*******************************************************************}
{                                                                   }
{       Developer Express .NET Component Library                    }
{       AgDataGrid                                 }
{                                                                   }
{       Copyright (c) 2000-2008 Developer Express Inc.              }
{       ALL RIGHTS RESERVED                                         }
{                                                                   }
{   The entire contents of this file is protected by U.S. and       }
{   International Copyright Laws. Unauthorized reproduction,        }
{   reverse-engineering, and distribution of all or any portion of  }
{   the code contained in this file is strictly prohibited and may  }
{   result in severe civil and criminal penalties and will be       }
{   prosecuted to the maximum extent possible under the law.        }
{                                                                   }
{   RESTRICTIONS                                                    }
{                                                                   }
{   THIS SOURCE CODE AND ALL RESULTING INTERMEDIATE FILES           }
{   ARE CONFIDENTIAL AND PROPRIETARY TRADE                          }
{   SECRETS OF DEVELOPER EXPRESS INC. THE REGISTERED DEVELOPER IS   }
{   LICENSED TO DISTRIBUTE THE PRODUCT AND ALL ACCOMPANYING .NET    }
{   CONTROLS AS PART OF AN EXECUTABLE PROGRAM ONLY.                 }
{                                                                   }
{   THE SOURCE CODE CONTAINED WITHIN THIS FILE AND ALL RELATED      }
{   FILES OR ANY PORTION OF ITS CONTENTS SHALL AT NO TIME BE        }
{   COPIED, TRANSFERRED, SOLD, DISTRIBUTED, OR OTHERWISE MADE       }
{   AVAILABLE TO OTHER INDIVIDUALS WITHOUT EXPRESS WRITTEN CONSENT  }
{   AND PERMISSION FROM DEVELOPER EXPRESS INC.                      }
{                                                                   }
{   CONSULT THE END USER LICENSE AGREEMENT FOR INFORMATION ON       }
{   ADDITIONAL RESTRICTIONS.                                        }
{                                                                   }
{*******************************************************************}
*/
#endregion Copyright (c) 2000-2008 Developer Express Inc.

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Globalization;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Threading;
using System.IO;
using System.Xml.Serialization;
using System.Xml;
using System.Xml.Linq;
using System.Windows.Media.Imaging;
using System.Windows.Media;
using System.Windows.Shapes;
namespace DevExpress.AgMenu.Utils {
	public static class RootVisualHelper {
		public static UIElement RootVisual { get { return Application.Current.RootVisual; } }
		public static event MouseButtonEventHandler OnClick;
		public static void SubscribeOnClick() {
			UnsubscribeOnClick();
			SubscribeOnClick(RootVisual);
		}
		public static void UnsubscribeOnClick() {
			UnsubscribeOnClick(RootVisual);
		}
		public static void SubscribeOnClick(DependencyObject o) {
			if(o == null) return;
			UIElement elem = o as UIElement;
			if(elem != null) elem.MouseLeftButtonDown += MouseLeftButtonDownHandler;
			for(int i = 0; i < VisualTreeHelper.GetChildrenCount(o); i++) {
				DependencyObject child = VisualTreeHelper.GetChild(o, i);
				if(child != null) SubscribeOnClick(child);
			}
		}
		public static void UnsubscribeOnClick(DependencyObject o) {
			if(o == null) return;
			UIElement elem = o as UIElement;
			if(elem != null) elem.MouseLeftButtonDown -= MouseLeftButtonDownHandler;
			for(int i = 0; i < VisualTreeHelper.GetChildrenCount(o); i++) {
				DependencyObject child = VisualTreeHelper.GetChild(o, i);
				if(child != null) UnsubscribeOnClick(child);
			}
		}
		static void MouseLeftButtonDownHandler(object sender, MouseButtonEventArgs e) {
			if(OnClick != null) {
				OnClick(sender, e);
			}
		}
	}
	public static class UIElementExtensions {
		public static bool GetVisible(this UIElement element) {
			return element.Visibility == Visibility.Visible;
		}
		public static void SetVisible(this UIElement element, bool visible) {
			element.Visibility = visible ? Visibility.Visible : Visibility.Collapsed;
		}
		public static Size GetDesiredSize(this UIElement element) {
			return GetVisualSize(element.DesiredSize);
		}
		public static Size GetRenderSize(this UIElement element) {
			return GetVisualSize(element.RenderSize);
		}
		public static double GetVisualSize(double size) {
			return Math.Ceiling(size);
		}
		public static Size GetVisualSize(Size size) {
			return new Size(Math.Ceiling(size.Width), Math.Ceiling(size.Height));
		}
		public static bool HasDefaultRenderTransform(this UIElement element) {
			return element.RenderTransform == null ||
				element.RenderTransform is MatrixTransform && ((MatrixTransform)element.RenderTransform).Matrix.IsIdentity;
		}
	}
	public static class FrameworkElementExtension {
		public static double GetLeft(this FrameworkElement element) {
			return GetPosition(element).X;
		}
		public static double GetTop(this FrameworkElement element) {
			return GetPosition(element).Y;
		}
		public static void SetLeft(this FrameworkElement element, double value) {
			Canvas.SetLeft(element, value);
		}
		public static void SetTop(this FrameworkElement element, double value) {
			Canvas.SetTop(element, value);
		}
		public static Point GetPosition(this FrameworkElement element) {
			return element.GetPosition(element.GetParent() as FrameworkElement);
		}
		public static Point GetPosition(this FrameworkElement element, FrameworkElement relativeTo) {
			return element.MapPoint(new Point(0, 0), relativeTo);
		}
		public static Point MapPoint(this FrameworkElement element, Point p, FrameworkElement destination) {
			if (destination == null)
				destination = (FrameworkElement)Application.Current.RootVisual;
			return element.TransformToVisual(destination).Transform(p);
		}
		public static Size GetSize(this FrameworkElement element) {
			return new Size(element.ActualWidth, element.ActualHeight);
		}
		public static void SetSize(this FrameworkElement element, Size value) {
			element.Width = value.Width;
			element.Height = value.Height;
		}
		public static Rect GetBounds(this FrameworkElement element) {
			return RectHelper.New(element.GetPosition(), element.GetSize());
		}
		public static Rect GetBounds(this FrameworkElement element, FrameworkElement relativeTo) {
			return RectHelper.New(element.GetPosition(relativeTo), element.GetSize());
		}
		public static void SetBounds(this FrameworkElement element, Rect bounds) {
			if (!bounds.IsEmpty) {
				element.SetLeft(bounds.Left);
				element.SetTop(bounds.Top);
			}
			element.Width = bounds.Width;
			element.Height = bounds.Height;
		}
		public static FrameworkElement GetParent(this FrameworkElement element) {
			return (FrameworkElement)(VisualTreeHelper.GetParent(element) ?? element.Parent);
		}
		public static bool IsVisible(this FrameworkElement element, FrameworkElement parent) {
			if (parent == null)
				parent = (FrameworkElement)Application.Current.RootVisual;
			bool result;
			do {
				if (element == null)
					return false;
				result = element.GetVisible();
				element = element.GetParent();
			}
			while (result && element != parent);
			return result;
		}
		public static int GetZIndex(this FrameworkElement element) {
			return Canvas.GetZIndex(element);
		}
		public static void SetZIndex(this FrameworkElement element, int value) {
			Canvas.SetZIndex(element, value);
		}
		public static void SetParent(this FrameworkElement element, DependencyObject value) {
			if (element.GetParent() == value)
				return;
			if (element.GetParent() is System.Windows.Controls.Panel)
				((System.Windows.Controls.Panel)element.GetParent()).Children.Remove(element);
			if (value is System.Windows.Controls.Panel)
				((System.Windows.Controls.Panel)value).Children.Add(element);
		}
		public static void ClipToBounds(this FrameworkElement element) {
			element.Clip = new RectangleGeometry { Rect = RectHelper.New(element.GetSize()) };
		}
		public static bool HasMouse(this FrameworkElement element, Point absoluteMousePosition) {
			return false;	
		}
		public static Rect GetBoundsNew(this FrameworkElement element, FrameworkElement parent) {
			return RectHelper.New(element.GetPositionNew(parent), element.GetSize());
		}
		public static Point GetPositionNew(this FrameworkElement element, FrameworkElement parent) {
			if (element is Popup)
				return new Point();
			if (FindParent(element, typeof(Popup)) == null) {
				if (parent == null)
					parent = (FrameworkElement)Application.Current.RootVisual;
				return element.TransformToVisual(parent).Transform(new Point());
			}
			return GetPositionNew2(element, parent);
		}
		static Point GetPositionNew2(this FrameworkElement element, FrameworkElement parent) {
			Point result;
			FrameworkElement tempParent = element.GetParent();
			if (tempParent is Popup)
				result = new Point((tempParent as Popup).HorizontalOffset, (tempParent as Popup).VerticalOffset);
			else
				if (element is Canvas)
					result = new Point();
				else {
					Rect r = LayoutInformation.GetLayoutSlot(element);
					result = new Point(r.Left, r.Top);
				}
			result = new Point(result.X + element.Margin.Left, result.Y + element.Margin.Top);
			if (tempParent != null && tempParent != parent) {
				Point p = GetPositionNew(tempParent, parent);
				result = new Point(result.X + p.X, result.Y + p.Y);
			}
			return result;
		}
		public static object FindParent(this FrameworkElement element, Type parentType) {
			FrameworkElement parent = element.GetParent();
			while (parent != null && !parentType.IsInstanceOfType(parent))
				parent = parent.GetParent();
			return parent;
		}
		public static void ClearParent(this FrameworkElement element) {
			if (element.GetParent() is System.Windows.Controls.Panel)
				(element.GetParent() as System.Windows.Controls.Panel).Children.Remove(element);
			else
				if (element.GetParent() is ContentPresenter && (element.GetParent() as ContentPresenter).Content == element)
					(element.GetParent() as ContentPresenter).Content = null;
		}
	}
	public static class BorderExtensions {
		public static Geometry GetChildClip(this Border border) {
			if (border.Child == null)
				return null;
			var rect = RectHelper.New(border.GetSize());
			RectHelper.Deflate(ref rect, border.BorderThickness);
			RectHelper.SetLocation(ref rect, border.MapPoint(RectHelper.Location(rect), (FrameworkElement)border.Child));
			var cornerRadius = border.CornerRadius;
			var borderThickness = border.BorderThickness;
			var corner = new Size[]
			{
				new Size(Math.Max(0, cornerRadius.TopLeft - borderThickness.Left / 2), Math.Max(0, cornerRadius.TopLeft - borderThickness.Top / 2)),
				new Size(Math.Max(0, cornerRadius.TopRight - borderThickness.Right / 2), Math.Max(0, cornerRadius.TopRight - borderThickness.Top / 2)),
				new Size(Math.Max(0, cornerRadius.BottomRight - borderThickness.Right / 2), Math.Max(0, cornerRadius.BottomRight - borderThickness.Bottom / 2)),
				new Size(Math.Max(0, cornerRadius.BottomLeft - borderThickness.Left / 2), Math.Max(0, cornerRadius.BottomLeft - borderThickness.Bottom / 2))
			};
			var figure = new PathFigure { IsClosed = true };
			figure.StartPoint = new Point(rect.Left, rect.Top + corner[0].Height);
			figure.Segments.Add(new ArcSegment {
				Point = new Point(rect.Left + corner[0].Width, rect.Top),
				Size = corner[0],
				SweepDirection = SweepDirection.Clockwise
			});
			figure.Segments.Add(new LineSegment { Point = new Point(rect.Right - corner[1].Width, rect.Top) });
			figure.Segments.Add(new ArcSegment {
				Point = new Point(rect.Right, rect.Top + corner[1].Height),
				Size = corner[1],
				SweepDirection = SweepDirection.Clockwise
			});
			figure.Segments.Add(new LineSegment { Point = new Point(rect.Right, rect.Bottom - corner[2].Height) });
			figure.Segments.Add(new ArcSegment {
				Point = new Point(rect.Right - corner[2].Width, rect.Bottom),
				Size = corner[2],
				SweepDirection = SweepDirection.Clockwise
			});
			figure.Segments.Add(new LineSegment { Point = new Point(rect.Left + corner[3].Width, rect.Bottom) });
			figure.Segments.Add(new ArcSegment {
				Point = new Point(rect.Left, rect.Bottom - corner[3].Height),
				Size = corner[3],
				SweepDirection = SweepDirection.Clockwise
			});
			var result = new PathGeometry();
			result.Figures.Add(figure);
			return result;
		}
	}
	public static class PopupExtensions {
		public static void MakeVisible(this Popup popup) {
			var popupSize = ((FrameworkElement)popup.Child).RenderSize;
			popup.HorizontalOffset = Math.Max(0, Math.Min(popup.HorizontalOffset, Application.Current.Host.Content.ActualWidth - popupSize.Width));
			popup.VerticalOffset = Math.Max(0, Math.Min(popup.VerticalOffset, Application.Current.Host.Content.ActualHeight - popupSize.Height));
		}
	}
	public static class PointHelper {
		public static bool IsEmpty(Point p) {
			return p == Empty;
		}
		public static Point Add(Point p1, Point p2) {
			return new Point(p1.X + p2.X, p1.Y + p2.Y);
		}
		public static void Offset(ref Point p, double x, double y) {
			p.X += x;
			p.Y += y;
		}
		public static Point Subtract(Point p1, Point p2) {
			return new Point(p1.X - p2.X, p1.Y - p2.Y);
		}
		public static Point Empty { get { return RectHelper.TopLeft(Rect.Empty); } }
	}
	public static class RectHelper {
		public static Rect New(Size size) {
			return new Rect(0, 0, size.Width, size.Height);
		}
		public static Rect New(Point location, Size size) {
			return new Rect(location.X, location.Y, size.Width, size.Height);
		}
		public static Point TopLeft(Rect rect) {
			return new Point(rect.Left, rect.Top);
		}
		public static Point BottomRight(Rect rect) {
			return new Point(rect.Right, rect.Bottom);
		}
		public static Point Location(Rect rect) {
			return TopLeft(rect);
		}
		public static void SetLocation(ref Rect rect, Point location) {
			rect.X = location.X;
			rect.Y = location.Y;
		}
		public static Size Size(Rect rect) {
			if (rect.IsEmpty)
				return System.Windows.Size.Empty;
			else
				return new Size(rect.Width, rect.Height);
		}
		public static void IncLeft(ref Rect rect, double value) {
			SetLeft(ref rect, rect.Left + value);
		}
		public static void IncTop(ref Rect rect, double value) {
			SetTop(ref rect, rect.Top + value);
		}
		public static void SetLeft(ref Rect rect, double left) {
			if (!double.IsInfinity(rect.Width))
				rect.Width = Math.Max(0, rect.Width - (left - rect.Left));
			rect.X = left;
		}
		public static void SetRight(ref Rect rect, double right) {
			rect.Width = Math.Max(0, right - rect.Left);
		}
		public static void SetTop(ref Rect rect, double top) {
			if (!double.IsInfinity(rect.Height))
				rect.Height = Math.Max(0, rect.Height - (top - rect.Top));
			rect.Y = top;
		}
		public static void SetBottom(ref Rect rect, double bottom) {
			rect.Height = Math.Max(0, bottom - rect.Top);
		}
		public static void Inflate(ref Rect rect, double x, double y) {
			rect.X -= x;
			rect.Y -= y;
			rect.Width += 2 * x;
			rect.Height += 2 * y;
		}
		public static void Inflate(ref Rect rect, Side side, double value) {
			switch (side) {
				case Side.Left:
					IncLeft(ref rect, -value);
					return;
				case Side.Top:
					IncTop(ref rect, -value);
					return;
				case Side.Right:
					rect.Width += value;
					return;
				case Side.Bottom:
					rect.Height += value;
					return;
			}
		}
		public static void Offset(ref Rect rect, double x, double y) {
			rect.X += x;
			rect.Y += y;
		}
		public static void Union(ref Rect rect, Rect value) {
			if (!double.IsNaN(value.Left))
				RectHelper.SetLeft(ref rect, Math.Min(rect.Left, value.Left));
			if (!double.IsNaN(value.Top))
				RectHelper.SetTop(ref rect, Math.Min(rect.Top, value.Top));
			if (!double.IsNaN(value.Right))
				RectHelper.SetRight(ref rect, Math.Max(rect.Right, value.Right));
			if (!double.IsNaN(value.Bottom))
				RectHelper.SetBottom(ref rect, Math.Max(rect.Bottom, value.Bottom));
		}
		public static void AlignHorizontally(ref Rect rect, Rect area, HorizontalAlignment alignment) {
			switch (alignment) {
				case HorizontalAlignment.Left:
					rect.X = area.Left;
					break;
				case HorizontalAlignment.Center:
					rect.X = Math.Round((area.Left + area.Right - rect.Width) / 2);
					break;
				case HorizontalAlignment.Right:
					rect.X = Math.Floor(area.Right - rect.Width);
					break;
				case HorizontalAlignment.Stretch:
					rect.X = area.Left;
					rect.Width = area.Width;
					break;
			}
		}
		public static void AlignVertically(ref Rect rect, Rect area, VerticalAlignment alignment) {
			switch (alignment) {
				case VerticalAlignment.Top:
					rect.Y = area.Top;
					break;
				case VerticalAlignment.Center:
					rect.Y = Math.Round((area.Top + area.Bottom - rect.Height) / 2);
					break;
				case VerticalAlignment.Bottom:
					rect.Y = Math.Floor(area.Bottom - rect.Height);
					break;
				case VerticalAlignment.Stretch:
					rect.Y = area.Top;
					rect.Height = area.Height;
					break;
			}
		}
		public static void Deflate(ref Rect rect, Thickness padding) {
			rect.X += padding.Left;
			rect.Y += padding.Top;
			rect.Width = Math.Max(0, rect.Width - (padding.Left + padding.Right));
			rect.Height = Math.Max(0, rect.Height - (padding.Top + padding.Bottom));
		}
		public static void Inflate(ref Rect rect, Thickness padding) {
			rect.X -= padding.Left;
			rect.Y -= padding.Top;
			rect.Width += padding.Left + padding.Right;
			rect.Height += padding.Top + padding.Bottom;
		}
		public static void SnapToDevicePixels(ref Rect rect) {
			rect.Width = UIElementExtensions.GetVisualSize(rect.Width);
			rect.Height = UIElementExtensions.GetVisualSize(rect.Height);
		}
		public static double GetSideOffset(Rect rect, Side side) {
			switch (side) {
				case Side.Left:
					return rect.Left;
				case Side.Top:
					return rect.Top;
				case Side.Right:
					return rect.Right;
				case Side.Bottom:
					return rect.Bottom;
				default:
					return double.NaN;
			}
		}
	}
	public static class SizeHelper {
		public static Size Infinite {
			get { return new Size(double.PositiveInfinity, double.PositiveInfinity); }
		}
		public static void Deflate(ref Size size, Thickness padding) {
			size.Width = Math.Max(0, size.Width - (padding.Left + padding.Right));
			size.Height = Math.Max(0, size.Height - (padding.Top + padding.Bottom));
		}
		public static void Inflate(ref Size size, Thickness padding) {
			size.Width += padding.Left + padding.Right;
			size.Height += padding.Top + padding.Bottom;
		}
		public static void UpdateMaxSize(ref Size maxSize, Size size) {
			UpdateMaxSize(ref maxSize, size, true, true);
		}
		public static void UpdateMaxSize(ref Size maxSize, Size size, bool updateWidth, bool updateHeight) {
			if (updateWidth)
				maxSize.Width = Math.Max(maxSize.Width, size.Width);
			if (updateHeight)
				maxSize.Height = Math.Max(maxSize.Height, size.Height);
		}
	}
	public static class ItemsControlExtensions {
		public static void MoveItemsTo(this ItemsControl from, ItemsControl to) {
			if (from.ItemsSource != null) {
				to.ItemsSource = from.ItemsSource;
				from.ItemsSource = null;
			} else
				if (from.Items.Count > 0)
					for (int i = from.Items.Count - 1; i >= 0; i--) {
						object item = from.Items[i];
						from.Items.RemoveAt(i);
						to.Items.Insert(0, item);
					}
		}
	}
}
